package org.reborn.demo

import org.reborn.engine.app._
import org.reborn.engine.render._

import org.reborn.math.VectorF
import org.reborn.math.Plane3F

import scala.math
import scala.List

import org.reborn.engine.model.mesh.Mesh
import org.reborn.engine.model.mesh.MutableMesh
import org.reborn.engine.model.mesh.ImmutableMesh
import org.reborn.engine.model.mesh.MeshUtil
import org.reborn.engine.model.mesh.VertexData
import org.reborn.engine.model.mesh.ImmutableVertexData
import org.reborn.engine.enums.ArrayType
import org.reborn.engine.enums.FaceMode
import org.reborn.engine.enums.UpdateFrequency

import org.reborn.utils.HeightMapUtil._
import org.reborn.engine.render.util._
import org.reborn.utils.Util._
import org.reborn.Constants._

import java.awt._
import java.awt.event._;

import javax.media.opengl._
import javax.media.opengl.GL
import javax.media.opengl.glu._
import com.jogamp.opengl.util._
import com.jogamp.opengl.util.awt.TextRenderer

object PartitionMesh extends GLApp {
  
  def main(args:Array[String]){
	
    val options = new GLAppOptions()
    options.title = "Partition Mesh Test"
    //options.fullscreen = false
    options.debugGL = true
    
	PartitionMesh.startApp(options)
  }
  
  import GL._
  import GL2GL3._
  val hm = Scale(DiamondSquare(4,0.45f,0.0f,0.5f),-0.25f,1.25f)
    
  var dRot = 0.0f
  val text = new TextRenderer(new Font("SansSerif", Font.BOLD, 20))
  
  var meshId = -1;
  var mesh:MutableMesh = null;
  
  var fpsAvg = 0.0f;
  var dt = 0.0f;
  
  override def initScene(drawable:GLAutoDrawable){
    val gl = drawable.getGL.getGL2
    import gl._
    
    //util.useMeshRendererIfAvailable(gl,RenderMeshVertexArrayRange)
    
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)
    glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
    glClearColor(0.2f,0.2f,0.2f,1.0f)
    
    val vertArray = new Array[Float](hm.length * hm.length * 3)
    val colArray = new Array[Float](hm.length * hm.length * 3)
    val faceArray = new Array[Int]((hm.length-1) * (hm.length-1) * 6)
    
    var curIndex = 0;
    var curPoly = 0;
    for(x <- 0 until hm.length;
        y <- 0 until hm.length){
          val fX = -1.0f + (x.asInstanceOf[Float] / hm.length.asInstanceOf[Float]) * 2.0f
          val fZ = -1.0f + (y.asInstanceOf[Float] / hm.length.asInstanceOf[Float]) * 2.0f
          val fY = hm(x,y,true) * 2.0f
          
          vertArray(curIndex*3) = fX
          vertArray(curIndex*3+1) = fY 
          vertArray(curIndex*3+2) = fZ
          
          var cR = 0.0f
          var cG = 0.0f
          var cB = 0.0f
          
          if(fY<=0.2f)          { cR=0.5f; cG=0.5f; cB=1.0f}
          if(fY>0.2f && fY<=.4) { cR=0.5f; cG=1.0f; cB=0.5f}
          if(fY>0.4f && fY<=.6) { cR=1.0f; cG=1.0f; cB=0.5f}
          if(fY>0.6f && fY<=.8) { cR=1.0f; cG=0.5f; cB=0.5f}
          if(fY>.8)             { cR=1.0f; cG=1.0f; cB=1.0f}  
          
          vertArray(curIndex*3+1) = fY
          
          colArray(curIndex*3) = cR
          colArray(curIndex*3+1) = cG
          colArray(curIndex*3+2) = cB
          
          if(x < (hm.length -1) && y < (hm.length -1)){
            val leftBot = x * hm.length + y
            val rightBot = (x+1) * hm.length + y
            val rightTop = (x+1) * hm.length + y + 1
            val leftTop = x * hm.length + y + 1
            faceArray(curPoly) = leftBot
            faceArray(curPoly+1) = rightBot
            faceArray(curPoly+2) = rightTop
            faceArray(curPoly+3) = rightTop
            faceArray(curPoly+4) = leftTop
            faceArray(curPoly+5) = leftBot
            curPoly+=6;
          }

          curIndex = curIndex+1;
    }
    
    mesh = new MutableMesh(FaceMode.Triangle,faceArray.length / 3, 100)
    mesh.replaceFaceData(faceArray)
    mesh.replaceVertData(ArrayType.Vertex,3,vertArray)
    mesh.replaceVertData(ArrayType.Color,3,colArray)

   
   
    util.useMeshRendererIfAvailable(gl,RenderMeshVertexArrayRange)
  }
  
  override def updateLogic(seconds:Float){
    fpsAvg = ((25.0f * fpsAvg) + seconds) / 26.0f
    this.dt = seconds;
    
    dRot = dRot + seconds * 0.1f

  }
  
  override def renderScene(drawable:GLAutoDrawable){
    val gl = drawable.getGL.getGL2
    import gl._
    
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
    glLoadIdentity();
    glTranslatef(0.0f,0.0f,-2.0f)
    
    glRotatef(30.0f,1.0f,0.0f,0.0f)
    //glRotatef(90.0f,1.0f,0.0f,0.0f)
    glRotatef(dRot*10.0f,0.0f,1.0f,0.0f)

    glScalef(1.0f,0.5f,1.0f)
    glTranslatef(0.0f,-.5f,0.0f)
    glColor3f(1.0f,1.0f,1.0f)
    
   var plane = new Plane3F(
	  VectorF(List(0.0f,0.5f,0.0f)),
	  VectorF(List(math.sin(dRot*4.0).asInstanceOf[Float] + math.sin(dRot).asInstanceOf[Float],math.cos(dRot*4.0).asInstanceOf[Float],math.cos(dRot).asInstanceOf[Float])).normalize);

    var (nMesh,pMesh) = MeshUtil.partition(mesh,plane,0.001f);

    
    if(pMesh.faces > 0){
    	val pMeshId = util.meshRenderer.register(gl,pMesh,UpdateFrequency.EachFrame)
    	
	    util.meshRenderer.render(gl,pMeshId)
	    
	    util.meshRenderer.unregister(gl,pMeshId)
    }
    if(nMesh.faces > 0 ){
	    meshId = util.meshRenderer.register(gl,nMesh,UpdateFrequency.EachFrame)
	    
	    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	    util.meshRenderer.render(gl,meshId)
	    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	    
	    util.meshRenderer.unregister(gl,meshId)
    }
    
    text beginRendering(drawable.getWidth, drawable.getHeight)
    text setColor(1.0f, 1.0f, 1.0f, 1.0f);
    text draw("" + 1.0f/dt,0,0);
    text draw("" + 1.0f/fpsAvg,0,16);
    text endRendering
      
    glFlush
  }
}